CATEGORIES = require('categories')

GLOBAL.STRINGS.INFINITE_ITEMS = {
    REGULATIONS = {
        VANILLA = {
            PREFAB = {
                MISSING = "missing_prefab",
                INVALID = "invalid_prefab",
            },
            NAME = {
                NO_PREFAB = "Missing Equipment",
                INVALID_PREFAB = "Invalid Equipment",
                INVALID = "Unknown Equipment",
            },
        },
        MODDED = {
            PREFAB = {
                MISSING = "missing_modded_prefab",
                invalid = "invalid_modded_prefab",
            },
            NAME = {
                NO_PREFAB = "Missing Modded Equipment",
                INVALID_PREFAB = "Invalid Modded Equipment",
                INVALID = "Unknown Modded Equipment",
            },
            MODNAME = {
                INVALID_PREFAB = "Invalid Modded Equipments",
                INVALID = "Unknown Mod",
            },
        },
    },
    SORTING = {
        VANILLA_LABEL = "VANILLA ITEMS",
        VANILLA_FRACTURED_LABEL = "Invalid Equipments",

        MODDED_LABEL = "MODDED ITEMS",
        MODDED_FRACTURED_LABEL = "Invalid Modded Equipments",
        MODDED_UNKNOWN_LABEL = "Invalid Modname Equipments",
    },
}



-- 自动消失时间
local disappearTime = TUNING.TOTAL_DAY_TIME * GetModConfigData("AUTO_PERISH_TIME")
local timer_name = "infinite_items_perish_timer"

local function OnDropped(inst)
    inst.components.timer:StartTimer(timer_name, disappearTime)
end

local function OnPickup(inst)
    inst.components.timer:StopTimer(timer_name)
end

local function OnTimerDone(inst, data)
    if data and data.name == timer_name then
        local x,y,z = inst:GetPosition():Get()
        GLOBAL.SpawnPrefab("small_puff").Transform:SetPosition(x,y,z)
        inst:Remove()
    end
end

----------------------------------------------------------------------

local function DeltaLock(inst, comp, subfn, flrfn)
    local oldfn = inst.components[comp][subfn]
    inst.components[comp][subfn] = function(first, secnd, ...)
        oldfn(first, type(secnd) == "number" and math.max(secnd, flrfn()) or secnd, ...)
    end
end

local function InitInfinite(inst)
    local DoNothing = function() end

    -- 隐藏百分比
    inst:AddTag("hide_percentage")

    -- 1. 易腐
    local perishable = inst.components.perishable
    if perishable then
        perishable.ReducePercent      = DoNothing
        perishable.localPerishMultiplyer = 0
        perishable.Dilute             = DoNothing
        perishable.perishremainingtime = perishable.perishtime
        perishable.OnRemoveFromEntity = function()
            inst:RemoveTag("fresh")
            inst:RemoveTag("stale")
            inst:RemoveTag("spoiled")
        end
        perishable.OnRemoveFromEntity()
        inst:RemoveTag("icebox_valid")
        inst:RemoveTag("show_spoilage")
    end

    -- 2. 盔甲
    if inst.components.armor then
        inst.components.armor.indestructible = true
    end

    -- 3. finiteuses（普通工具、武器）
    local finiteuses = inst.components.finiteuses
    if finiteuses then
        local oldSet = finiteuses.SetUses
        finiteuses.SetUses = function(self, val, ...)
            oldSet(self, type(val) == "number" and math.max(val, finiteuses.current) or val, ...)
        end
    end

    -- 4. 武器攻击耐久
    if inst.components.weapon then
        inst.components.weapon.attackwear = 0
    end

    -- 5. 燃料
    local fueled = inst.components.fueled
    if fueled then
        local oldDelta = fueled.DoDelta
        fueled.DoDelta = function(self, val, ...)
            oldDelta(self, type(val) == "number" and math.max(val, 0) or val, ...)
        end
        fueled.rate_modifiers:SetModifier(inst, 0)
    end

    -- 6. 自动消失计时
    if GetModConfigData("AUTO_PERISH_TIME") > 0 and inst.components.inventoryitem then
        if not inst.components.timer then
            inst:AddComponent("timer")
        end
        inst.components.inventoryitem:SetOnPutInInventoryFn(OnPickup)
        inst:ListenForEvent("ondropped", OnDropped)
        inst:ListenForEvent("timerdone", OnTimerDone)
        inst.components.timer:StartTimer(timer_name, disappearTime)
    end
end

local function MakeInfinite(inst)
    InitInfinite(inst)
    local upgradeable = inst.components.upgradeable
    if upgradeable then
        -- 升级后重新锁耐久
        local old_onupgrade = upgradeable.onupgradefn
        upgradeable.onupgradefn = function(inst, ...)
            if old_onupgrade then old_onupgrade(inst, ...) end
            InitInfinite(inst)
        end
        -- 读档后重新锁耐久
        local old_onload = inst.OnLoad
        inst.OnLoad = function(inst, ...)
            if old_onload then old_onload(inst, ...) end
            InitInfinite(inst)
        end
    end
end

local function SetPrefabPerishRate(prefab, rate)
    AddPrefabPostInit(prefab, function(inst)
        if inst.components.preserver == nil then
            inst:AddComponent("preserver")
        end
        inst.components.preserver:SetPerishRateMultiplier(rate)
    end)
end

local function ListFix(list)
    for _,v in pairs(CATEGORIES[list]) do
        if v.prefab and GetModConfigData('INFINITE_'..string.upper(v.prefab)) then
            AddPrefabPostInit(v.prefab, MakeInfinite)
        end
    end
end

ListFix("VANILLA")
ListFix("MODDED")

if GetModConfigData('INFINITE_TOOL1') then
    for _,v in pairs(CATEGORIES["INFINITE_TOOL1"]) do
        AddPrefabPostInit(v.prefab, MakeInfinite)
    end
end

if GetModConfigData('INFINITE_TOOL2') then
    for _,v in pairs(CATEGORIES["INFINITE_TOOL2"]) do
        AddPrefabPostInit(v.prefab, MakeInfinite)
    end
end

if GetModConfigData('INFINITE_TOOL3') then
    for _,v in pairs(CATEGORIES["INFINITE_TOOL3"]) do
        AddPrefabPostInit(v.prefab, MakeInfinite)
    end
end

--物品栏无限耐久
local function InitInfiniteInInventory(inst)
    InitInfinite(inst)

    if inst.components.inventoryitem ~= nil then
        local old_OnPutInInventory = inst.components.inventoryitem.onputininventoryfn
        inst.components.inventoryitem:SetOnPutInInventoryFn(function(inst, owner)
            if owner and owner:HasTag("player") then
                InitInfinite(inst)           -- 重新锁耐久
            end
            if old_OnPutInInventory then
                old_OnPutInInventory(inst, owner)
            end
        end)

        local old_OnDropped = inst.components.inventoryitem.ondroppedfn
        inst.components.inventoryitem:SetOnDroppedFn(function(inst)
            -- 掉出玩家物品栏，不再锁耐久（保持当前值即可）
            if old_OnDropped then
                old_OnDropped(inst)
            end
        end)
    end
end

if GetModConfigData("PLAYER_DURABILITY") then
    local function ApplyInventoryInfinite(list)
        for _, v in pairs(list or {}) do
            if v.prefab then
                AddPrefabPostInit(v.prefab, InitInfiniteInInventory)
            end
        end
    end

    ApplyInventoryInfinite(CATEGORIES.VANILLA)
    ApplyInventoryInfinite(CATEGORIES.MODDED)
end

local boat_health = GetModConfigData("BOAT_HEALTH")
TUNING.BOAT.HEALTH = boat_health

if GetModConfigData("CHANGE_FRESH") == 1 then
    local mushroomlight_fresh = GetModConfigData("MUSHROOMLIGHT_FRESH")
    local icebox_fresh = GetModConfigData("ICEBOX_FRESH")
    local saltbox_fresh = GetModConfigData("SALTBOX_FRESH")
    local birdcage_fresh = GetModConfigData("BIRDCAGE_FRESH")
    local sisturn_fresh = GetModConfigData("SISTURN_FRESH")
    local insulatedpack_fresh = GetModConfigData("INSULATEDPACK_FRESH")
    local spicepack_fresh = GetModConfigData("SPICEPACK_FRESH")
    local seedpack_fresh = GetModConfigData("SEEDPACK_FRESH")
    local beargerfursack_fresh = GetModConfigData("BEARGERFURSACK_FRESH")
    local treasurechest_fresh = GetModConfigData("TREASURECHEST_FRESH")
    local dragonflychest_fresh = GetModConfigData("DRAGONFLYCHEST_FRESH")
    local chester_fresh = GetModConfigData("CHESTER_FRESH")

    TUNING.PERISH_MUSHROOM_LIGHT_MULT = mushroomlight_fresh
    TUNING.PERISH_FRIDGE_MULT = icebox_fresh
    TUNING.PERISH_SALTBOX_MULT = saltbox_fresh
    TUNING.PERISH_CAGE_MULT = birdcage_fresh
    TUNING.BOAT.HEALTH = boat_health
    SetPrefabPerishRate("sisturn", sisturn_fresh)
    SetPrefabPerishRate("icepack", insulatedpack_fresh)
    SetPrefabPerishRate("spicepack", spicepack_fresh)
    SetPrefabPerishRate("seedpouch", seedpack_fresh)
    SetPrefabPerishRate("beargerfur_sack", beargerfursack_fresh)
    SetPrefabPerishRate("treasurechest", treasurechest_fresh)
    SetPrefabPerishRate("dragonflychest", dragonflychest_fresh)
end

--背包保鲜功能
local BACKPACK_RATE = GetModConfigData("BACKPACK_FRESH")
for _, prefab in ipairs({
    "backpack", "piggyback", "krampus_sack",
    "icepack", "spicepack", "seedpouch", "beargerfur_sack"
}) do
    AddPrefabPostInit(prefab, function(inst)
        local rate = GetModConfigData(string.upper(prefab) .. "_FRESH") or BACKPACK_RATE
        if not inst.components.preserver then inst:AddComponent("preserver") end
        inst.components.preserver:SetPerishRateMultiplier(rate)
    end)
end

-- 玩家物品栏保鲜倍率
local PLAYER_FRESH_RATE = GetModConfigData("PLAYER_FRESH")

local function SafeSetPerishRate(inst, rate)
    if inst and inst:IsValid() and inst.components and inst.components.perishable then
        inst.components.perishable.localPerishMultiplyer = rate
    end
end

-- 真正应用到单个物品的函数
local function ApplyFreshness(inst)
    -- 跳过没有保鲜组件的实体
    if not (inst and inst.components and inst.components.perishable) then return end
    
    -- 确保有 inventoryitem 组件
    if inst.components.inventoryitem then
        -- 保存原始回调
        local old_OnPutInInventory = inst.components.inventoryitem.onputininventoryfn
        local old_OnDropped = inst.components.inventoryitem.ondroppedfn
        
        -- 覆盖进入物品栏回调
        inst.components.inventoryitem.onputininventoryfn = function(inst, owner)
            if owner and owner:HasTag("player") then
                SafeSetPerishRate(inst, PLAYER_FRESH_RATE)
            end
            if old_OnPutInInventory then 
                old_OnPutInInventory(inst, owner)
            end
        end
        
        -- 覆盖离开物品栏回调
        inst.components.inventoryitem.ondroppedfn = function(inst)
            SafeSetPerishRate(inst, 1)
            if old_OnDropped then 
                old_OnDropped(inst)
            end
        end
    end
end

-- 对所有带保鲜度的物品生效
AddPrefabPostInitAny(ApplyFreshness)

-- 仅当物品栏永久保鲜(PLAYER_FRESH == 0)时，让活体动物在物品栏内不死亡
if GetModConfigData("PLAYER_FRESH") == 0 then
    AddPrefabPostInitAny(function(inst)
        -- 确保实体和组件存在
        if not (inst and inst.components and inst.components.perishable) then return end
        if not inst:HasTag("smallcreature") then return end
        
        -- 确保有 inventoryitem 组件
        if inst.components.inventoryitem then
            -- 保存原始回调
            local old_OnPutInInventory = inst.components.inventoryitem.onputininventoryfn
            local old_OnDropped = inst.components.inventoryitem.ondroppedfn
            
            -- 覆盖进入物品栏回调
            inst.components.inventoryitem.onputininventoryfn = function(inst, owner)
                if owner and owner:HasTag("player") then
                    SafeSetPerishRate(inst, 0)
                end
                if old_OnPutInInventory then 
                    old_OnPutInInventory(inst, owner)
                end
            end
            
            -- 覆盖离开物品栏回调
            inst.components.inventoryitem.ondroppedfn = function(inst)
                SafeSetPerishRate(inst, 1)
                if old_OnDropped then 
                    old_OnDropped(inst)
                end
            end
        end
    end)
end

--单独物品保鲜

local function SetItemPerishRate(prefab, rate)
    AddPrefabPostInit(prefab, function(inst)
        if inst.components.perishable then
            if rate == 0 then
                -- 永久新鲜
                inst.components.perishable.localPerishMultiplyer = 0
                inst.components.perishable.ReducePercent = function() end
                inst.components.perishable.Dilute = function() end
            else
                inst.components.perishable.localPerishMultiplyer = rate
            end
        end
    end)
end

local function GetSingleItemFreshRate(prefab)
    return GetModConfigData("FRESH_" .. string.upper(prefab or ""))
end

-- 综合保鲜倍率计算（单独物品保鲜、容器保鲜、玩家物品栏保鲜）
local function UpdatePerishRate(inst)
    if not (inst and inst.components and inst.components.perishable) then
        return
    end

    local base_rate = inst._base_perish_rate or 1
    local final_rate = base_rate

    local single_rate = GetSingleItemFreshRate(inst.prefab)
    if single_rate == 0 then
        final_rate = 0
    elseif single_rate then
        final_rate = final_rate * single_rate
    end

    if inst.components.inventoryitem and inst.components.inventoryitem:GetContainer() then
        local container = inst.components.inventoryitem:GetContainer()
        if container and container.components and container.components.preserver then
            final_rate = final_rate * container.components.preserver:GetPerishRateMultiplier()
        end
    end

    if inst.components.inventoryitem and inst.components.inventoryitem.owner and inst.components.inventoryitem.owner:HasTag("player") then
        final_rate = final_rate * PLAYER_FRESH_RATE
    end

    inst.components.perishable.localPerishMultiplyer = final_rate
end

AddPrefabPostInitAny(function(inst)
    -- 首先检查实体是否有效
    if not inst or not inst:IsValid() then return end

    -- 检查必要的组件是否存在
    if not (inst.components and inst.components.inventoryitem) then return end
    if not inst.components.perishable then return end

    -- 记录原始倍率
    inst._base_perish_rate = 1

    -- 定义安全更新函数
    local function SafeUpdatePerishRate(inst)
        if inst and inst:IsValid() and inst.components and inst.components.perishable then
            UpdatePerishRate(inst)
        end
    end

    -- 监听进入/离开容器或物品栏
    -- 保存原始回调
    local old_OnPutInInventory = inst.components.inventoryitem.onputininventoryfn
    local old_OnDropped = inst.components.inventoryitem.ondroppedfn
    
    -- 设置新的回调
    inst.components.inventoryitem.onputininventoryfn = function(inst, owner)
        SafeUpdatePerishRate(inst)
        if old_OnPutInInventory then 
            old_OnPutInInventory(inst, owner)
        end
    end
    
    inst.components.inventoryitem.ondroppedfn = function(inst)
        SafeUpdatePerishRate(inst)
        if old_OnDropped then 
            old_OnDropped(inst)
        end
    end

    -- 初始状态（读档或生成）
    inst:DoTaskInTime(0, SafeUpdatePerishRate)
end)
